/*
 * Copyright (c) 2009, Jan Pastor. All Rights Reserved.
 */

package sk.jp.imageio.jpeg;

import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import sk.jp.commons.utils.LogMsg;

/**
 * Utilities for image manipulation.
 */
public class ImageUtil {

    private static final Logger log = LoggerFactory.getLogger(ImageUtil.class);

    private ImageUtil() {
    }

    /**
     * Create resized image from given source image.
     * @param image source image.
     * @param dimension required dimension.
     * @return resized image.
     */
    public static BufferedImage resize(BufferedImage image, Dimension dimension){
        log.debug(LogMsg.inp("dimension", dimension));
        
        double imgX = image.getWidth();
        double imgY = image.getHeight();
        double dimX = dimension.getWidth();
        double dimY = dimension.getHeight();

        if(imgX < dimX && imgY < dimY){
            return image;
        }

        double mx = dimX / imgX;
        double my = dimY / imgY;
        double m = Math.min(mx, my);

        AffineTransform transform;
        transform = new AffineTransform();
        transform.scale(m, m);

        AffineTransformOp transformOp = new AffineTransformOp(transform,
                                              AffineTransformOp.TYPE_BICUBIC);
        BufferedImage destImage = new BufferedImage((int)Math.round(imgX * m),
                                                    (int)Math.round(imgY * m),
                                                    image.getType());
        transformOp.filter(image, destImage);

        log.trace(LogMsg.out());
        return destImage;
    }

    /**
     * Create rotated image from given source image.
     * <p>This method performs only rotation about 90 degrees
     * to left (<code>rotateClockwise is false</code>) or right
     * (<code>rotateClockwise is true</code>).
     * @param image source image.
     * @param rotateClockwise rotation direction.
     * @return rotated image.
     */
    public static BufferedImage rotate(BufferedImage image, boolean rotateClockwise){
        log.debug(LogMsg.inp("rotateClockwise", rotateClockwise));

        int rc = rotateClockwise ? 1 : -1;
        AffineTransform transform;
        transform = new AffineTransform();
        int dx = image.getWidth();
        int dy = image.getHeight();
        transform.rotate(rc * Math.PI / 2.0, dx / 2.0, dy / 2.0);

        double t = (dx - dy) / 2.0;
        transform.translate(rc * t, rc * t);

        AffineTransformOp transformOp = new AffineTransformOp(transform,
                                              AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
        BufferedImage destImage = new BufferedImage(image.getHeight(), image.getWidth(),
                                                    image.getType());
        transformOp.filter(image, destImage);

        log.trace(LogMsg.out());
        return destImage;
    }

    /**
     * Reads picture data from file.
     * @param file
     * @return
     * @throws IOException
     */
    public static BufferedImage loadPictureData(File file) throws IOException {
        if(log.isDebugEnabled()){
            log.debug(LogMsg.inp("file", file));
        }
        BufferedImage bufferedImage;
        bufferedImage = ImageIO.read(file);
        if(log.isTraceEnabled()){
            log.trace(LogMsg.out());
        }
        return bufferedImage;
    }

}
